package com.deductive.netty.websocket.handler;

import cn.hutool.extra.spring.SpringUtil;
import com.deductive.netty.websocket.message.WebSocketMessage;
import com.deductive.netty.websocket.service.NettyConnectionManager;
import com.deductive.netty.websocket.service.WebSocketPushService;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class WebSocketFrameHandler extends SimpleChannelInboundHandler<WebSocketFrame> {

    private static final Logger logger = LoggerFactory.getLogger(WebSocketFrameHandler.class);
    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
        if (!(frame instanceof TextWebSocketFrame)) {
            String message = "不支持的帧类型: " + frame.getClass().getName();
            throw new UnsupportedOperationException(message);
        }

        String request = ((TextWebSocketFrame) frame).text();
        logger.info("接收到消息: {}", request);

        WebSocketMessage webSocketMessage;
        try {
            webSocketMessage = objectMapper.readValue(request, WebSocketMessage.class);
        } catch (JsonProcessingException e) {
            logger.error("解析WebSocket消息失败: {}", request, e);
            ctx.channel().writeAndFlush(new TextWebSocketFrame("{\"type\":\"ERROR\", \"payload\":\"消息格式无效\"}"));
            return;
        }

        String userId = NettyConnectionManager.getUserId(ctx.channel());

        switch (webSocketMessage.getType()) {
            case "AUTH":
                handleAuth(ctx, webSocketMessage);
                break;
            case "GET_ONLINE_USERS":
                handleGetOnlineUsers(ctx);
                break;
            default:
                if (userId == null) {
                    ctx.channel().writeAndFlush(new TextWebSocketFrame("{\"type\":\"ERROR\", \"payload\":\"未授权，请先进行身份验证\"}"));
                    ctx.close();
                    return;
                }
                handleData(ctx, userId, webSocketMessage);
                break;
        }
    }

    private void handleAuth(ChannelHandlerContext ctx, WebSocketMessage message) {
        JsonNode payload = message.getPayload();
        if (payload != null && payload.has("userId")) {
            String newUserId = payload.get("userId").asText();
            NettyConnectionManager.addChannel(newUserId, ctx.channel());
            ctx.channel().writeAndFlush(new TextWebSocketFrame("{\"type\":\"AUTH_SUCCESS\", \"payload\":\"用户 " + newUserId + " 认证成功\"}"));
            logger.info("用户 {} 在通道 {} 认证成功", newUserId, ctx.channel().id());

            // 广播用户上线消息
            WebSocketPushService pushService = SpringUtil.getBean(WebSocketPushService.class);
            if (pushService != null) {
                pushService.broadcastUserOnline(newUserId);
            }
        } else {
            ctx.channel().writeAndFlush(new TextWebSocketFrame("{\"type\":\"AUTH_FAILED\", \"payload\":\"载荷中缺少userId\"}"));
            ctx.close();
        }
    }

    private void handleGetOnlineUsers(ChannelHandlerContext ctx) {
        String userId = NettyConnectionManager.getUserId(ctx.channel());
        if (userId == null) {
            ctx.channel().writeAndFlush(new TextWebSocketFrame("{\"type\":\"ERROR\", \"payload\":\"未授权，无法获取在线列表\"}"));
            return;
        }

        Set<String> onlineUsers = NettyConnectionManager.getOnlineUsers();
        Map<String, Object> payload = new HashMap<>();
        payload.put("users", onlineUsers);

        Map<String, Object> responseMessage = new HashMap<>();
        responseMessage.put("type", "ONLINE_USERS_LIST");
        responseMessage.put("payload", payload);

        WebSocketPushService pushService = SpringUtil.getBean(WebSocketPushService.class);
        if (pushService != null) {
            pushService.pushToUser(userId, responseMessage);
        }
    }

    private void handleData(ChannelHandlerContext ctx, String userId, WebSocketMessage message) {
        logger.info("接收到来自用户 {} 的类型为 '{}' 的消息: {}", userId, message.getType(), message.getPayload());
        // 暂时将消息回显
        ctx.channel().writeAndFlush(new TextWebSocketFrame("{\"type\":\"ECHO\", \"payload\":\"" + message.getPayload().toString() + "\"}"));
    }

    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
        logger.info("通道 {} 已连接", ctx.channel().id());
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        String userId = NettyConnectionManager.getUserId(ctx.channel());
        NettyConnectionManager.removeChannel(ctx.channel());
        logger.info("通道 {} 已断开连接", ctx.channel().id());

        if (userId != null) {
            // 广播用户下线消息
            WebSocketPushService pushService = SpringUtil.getBean(WebSocketPushService.class);
            if (pushService != null) {
                pushService.broadcastUserOffline(userId);
            }
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        logger.error("通道 {} 捕获到异常", ctx.channel().id(), cause);
        NettyConnectionManager.removeChannel(ctx.channel());
        ctx.close();
    }
}
